#include "ftpprotocol.h"
#include <QDebug>
#include <QNetworkInterface>
#include <QRandomGenerator>
#include <QTcpServer>

// 定义静态常量
const QString FtpProtocol::LOG_PREFIX = "[FTP Protocol]";

FtpProtocol::FtpProtocol(QObject *parent) : QObject(parent)
{
    m_dataServer = nullptr;
    m_isPassiveMode = false;
    m_passivePort = 0;
    m_activePort = 0;
    m_isPassiveConnectionReused = false; // 初始化复用标记
    m_currentCommand = None; // 初始化当前命令为None

    initSockets();

    m_downloadFile = nullptr; // 初始化下载文件指针
    m_bytesReceived = 0;      // 初始化已下载字节数为0
}

FtpProtocol::~FtpProtocol()
{   
    disconnectFromHost();
    closeDataConnection();
    // 确保下载文件被正确关闭和释放
    if (m_downloadFile && m_downloadFile->isOpen()) {
        m_downloadFile->close();
        delete m_downloadFile;
        m_downloadFile = nullptr;
    }
}

void FtpProtocol::initSockets()
{
    m_controlSocket = new QTcpSocket(this);
    m_dataSocket = new QTcpSocket(this);

    // 连接控制套接字的信号与槽
    connect(m_controlSocket, &QTcpSocket::readyRead, this, &FtpProtocol::onControlSocketReadyRead);
    connect(m_controlSocket, &QTcpSocket::disconnected, this, &FtpProtocol::onControlSocketDisconnected);

    // 连接数据套接字的信号与槽
    connect(m_dataSocket, &QTcpSocket::connected, this, &FtpProtocol::onDataSocketConnected);
    connect(m_dataSocket, &QTcpSocket::readyRead, this, &FtpProtocol::onDataSocketReadyRead); // 连接数据接收信号
    connect(m_dataSocket, &QTcpSocket::disconnected, this, &FtpProtocol::onDataSocketDisconnected);
}

// 修改connectToHost方法中的日志
bool FtpProtocol::connectToHost(const QString &host, int port)
{
    FTP_PROTOCOL_DEBUG_FMT("正在连接到服务器:%s:%d", host.toUtf8().constData(), port);
    
    // 先断开现有连接
    disconnectFromHost();
    
    // 连接到服务器
    m_controlSocket->connectToHost(host, port);
    
    // 等待连接成功或超时
    if (!m_controlSocket->waitForConnected(5000)) {
        FTP_PROTOCOL_DEBUG_FMT("连接服务器失败:%s", m_controlSocket->errorString().toUtf8().constData());
        emit error(tr("连接服务器失败: %1,%2,%3").arg(m_controlSocket->errorString()).arg(host).arg(port));
        return false;
    }
    
    FTP_PROTOCOL_DEBUG("控制连接建立成功");
    return true;
}

// 修改disconnectFromHost方法中的日志
void FtpProtocol::disconnectFromHost()
{
    if (m_controlSocket->state() == QTcpSocket::ConnectedState) {
        FTP_PROTOCOL_DEBUG("断开控制连接");
        m_controlSocket->disconnectFromHost();
        m_controlSocket->waitForDisconnected();
    }
}

bool FtpProtocol::isConnected() const
{
    return m_controlSocket->state() == QTcpSocket::ConnectedState;
}


// 修改sendUSER方法中的日志
bool FtpProtocol::sendUSER(const QString &username)
{
    if (!isConnected())
        return false;
    
    QString command = QString("USER %1\r\n").arg(username);
    FTP_PROTOCOL_DEBUG_FMT("发送命令:%s", command.trimmed().toUtf8().constData());
    m_controlSocket->write(command.toUtf8());
    bool result = m_controlSocket->waitForBytesWritten();
    FTP_PROTOCOL_DEBUG_FMT("命令发送%s", (result ? "成功" : "失败"));
    return result;
}

// 修改sendPASS方法中的日志
bool FtpProtocol::sendPASS(const QString &password)
{
    if (!isConnected())
        return false;
    
    qDebug() << LOG_PREFIX << "发送命令: PASS ******";
    QString command = QString("PASS %1\r\n").arg(password);
    m_controlSocket->write(command.toUtf8());
    bool result = m_controlSocket->waitForBytesWritten();
    qDebug() << LOG_PREFIX << "密码发送" << (result ? "成功" : "失败");
    return result;
}

// 修改sendPASV方法中的日志
bool FtpProtocol::sendPASV()
{
    if (!isConnected())
        return false;
    
    m_isPassiveMode = true;
    qDebug() << LOG_PREFIX << "发送命令: PASV";
    m_controlSocket->write("PASV\r\n");
    bool result = m_controlSocket->waitForBytesWritten();
    qDebug() << LOG_PREFIX << "PASV命令发送" << (result ? "成功" : "失败");
    return result;
}

bool FtpProtocol::sendPASV2()
{
    if (!isConnected())
        return false;

    m_isPassiveMode = true;
    m_controlSocket->write("PASV2\r\n");
    return m_controlSocket->waitForBytesWritten();
}

// 修改sendPORT方法，使用保存的端口

// 修改sendPORT方法中的日志
bool FtpProtocol::sendPORT()
{
    if (!isConnected())
        return false;
    
    // 设置为非被动模式
    m_isPassiveMode = false;
    
    // 获取本地IP地址
    QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
    QHostAddress localAddress;
    
    // 找到合适的IPv4地址
    for (const QHostAddress &address : addresses) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol &&
            address != QHostAddress::LocalHost &&
            address != QHostAddress::LocalHostIPv6) {
            localAddress = address;
            break;
        }
    }
    
    // 如果没有找到合适的IP，使用localhost
    if (localAddress.isNull()) {
        localAddress = QHostAddress::LocalHost;
    }
    
    // 生成或使用已保存的端口号
    quint16 port;
    if (m_activePort > 0) {
        port = m_activePort;
    } else {
        port = 1024 + QRandomGenerator::global()->bounded(64511);
        m_activePort = port;
    }
    
    // 分解IP地址和端口号
    QStringList ipParts = localAddress.toString().split('.');
    int p1 = port / 256;
    int p2 = port % 256;
    
    // 构建PORT命令
    QString portCommand = QString("PORT %1,%2,%3,%4,%5,%6\r\n")
        .arg(ipParts[0]).arg(ipParts[1]).arg(ipParts[2]).arg(ipParts[3])
        .arg(p1).arg(p2);
    
    // 发送PORT命令
    m_controlSocket->write(portCommand.toUtf8());
    bool result = m_controlSocket->waitForBytesWritten();
    qDebug() << LOG_PREFIX << "PORT命令发送" << (result ? "成功" : "失败") << "，使用端口:" << port;
    return result;
}

bool FtpProtocol::sendFISTOR()
{
    if (!isConnected())
        return false;
    
    m_controlSocket->write("FISTOR\r\n");
    return m_controlSocket->waitForBytesWritten();
}

bool FtpProtocol::isDataConnectionActive() const
{
    return m_dataSocket->state() == QTcpSocket::ConnectedState;
}

bool FtpProtocol::establishDataConnection()
{
    // 如果数据连接已经建立，则直接返回成功
    if (isDataConnectionActive()) {
        return true;
    }

    // 先关闭现有数据连接
    closeDataConnection();

    if (m_isPassiveMode && !m_passiveAddress.isNull() && m_passivePort > 0) {
        // 被动模式：连接到服务器提供的地址和端口
        qDebug() << "[FTP Protocol] 被动模式连接到:" << m_passiveAddress.toString() << ":" << m_passivePort;
        m_dataSocket->connectToHost(m_passiveAddress, m_passivePort);
        bool connected = m_dataSocket->waitForConnected(3000);
        if (connected) {
            m_isPassiveConnectionReused = true; // 设置为可复用
            qDebug() << "[FTP Protocol] 数据连接建立成功（被动模式）";
            emit dataConnectionEstablished();
        } else {
            qDebug() << "[FTP Protocol] 数据连接建立失败:" << m_dataSocket->errorString();
        }
        return connected;
    }
    else {
        // 主动模式：监听本地端口等待服务器连接
        // 注意：这里需要先在FtpProtocol类中添加m_dataServer和m_activePort成员变量
        QTcpServer* dataServer = new QTcpServer(this);

        // 尝试绑定一个可用端口（使用与PORT命令相同的端口范围）
        quint16 port = 0;
        bool listening = false;

        // 尝试最多5次找到可用端口
        for (int i = 0; i < 5; i++) {
            port = 1024 + QRandomGenerator::global()->bounded(64511);
            if (dataServer->listen(QHostAddress::Any, port)) {
                listening = true;
                break;
            }
        }

        if (!listening) {
            delete dataServer;
            emit error(tr("无法建立数据连接: 无法绑定本地端口"));
            return false;
        }

        // 保存端口信息，在sendPORT中使用
        m_activePort = port;

        // 设置服务器连接处理
        connect(dataServer, &QTcpServer::newConnection, this, [=]() {
            if (dataServer->hasPendingConnections()) {
                // 接受连接
                QTcpSocket* newSocket = dataServer->nextPendingConnection();
        
                // 如果当前有数据套接字，先关闭
                if (m_dataSocket->state() == QTcpSocket::ConnectedState) {
                    m_dataSocket->disconnectFromHost();
                    m_dataSocket->waitForDisconnected();
                }
        
                // 替换数据套接字
                m_dataSocket->deleteLater();
                m_dataSocket = newSocket;
        
                // 连接信号与槽
                connect(m_dataSocket, &QTcpSocket::disconnected, this, &FtpProtocol::onDataSocketDisconnected);
                connect(m_dataSocket, &QTcpSocket::readyRead, this, &FtpProtocol::onDataSocketReadyRead); // 新增：连接新套接字的数据接收信号
        
                // 通知数据连接已建立
                emit dataConnectionEstablished();
        
                // 不再需要服务器，关闭并删除
                dataServer->close();
                dataServer->deleteLater();
            }
            });

        // 等待一段时间让服务器有机会连接
        // 注意：在实际应用中，这部分逻辑可能需要调整，因为这里不能阻塞太长时间
        return true; // 返回true，表示已准备好接受连接
    }
}

// 修改closeDataConnection方法，支持控制是否真正关闭连接
void FtpProtocol::closeDataConnection()
{
    if (m_dataSocket->state() == QTcpSocket::ConnectedState) {
        m_dataSocket->disconnectFromHost();
        m_dataSocket->waitForDisconnected();
        m_isPassiveConnectionReused = false; // 关闭后不可复用
    }
}

bool FtpProtocol::sendCWD(const QString &path)
{    if (!isConnected())
        return false;
    
    QString command = QString("CWD %1\r\n").arg(path);
    FTP_PROTOCOL_DEBUG_FMT("发送命令:%s", command.trimmed().toUtf8().constData());
    m_controlSocket->write(command.toUtf8());
    bool result = m_controlSocket->waitForBytesWritten();
    FTP_PROTOCOL_DEBUG_FMT("CWD命令发送%s", (result ? "成功" : "失败"));
    return result;
}

bool FtpProtocol::sendLIST(const QString &path)
{    if (!isConnected() || !establishDataConnection())
        return false;
    
    m_currentCommand = LIST; // 设置当前命令为LIST
    QString command = QString("LIST %1\r\n").arg(path);
    m_controlSocket->write(command.toUtf8());
    return m_controlSocket->waitForBytesWritten();
}

bool FtpProtocol::sendRETR(const QString &fileName, const QString &localFilePath)
{
    if (!isConnected() || !establishDataConnection())
        return false;
    
    m_currentCommand = RETR; // 设置当前命令为RETR
    m_currentFileName = fileName;
    m_bytesReceived = 0;     // 重置已下载字节数
    
    // 如果提供了本地文件路径，则打开文件准备写入
    if (!localFilePath.isEmpty()) {
        m_downloadFilePath = localFilePath;
        
        // 如果之前有打开的文件，先关闭
        if (m_downloadFile && m_downloadFile->isOpen()) {
            m_downloadFile->close();
            delete m_downloadFile;
        }
        
        // 创建新的文件对象并打开
        m_downloadFile = new QFile(localFilePath);
        if (!m_downloadFile->open(QIODevice::WriteOnly)) {
            emit error(tr("无法打开文件进行写入: %1").arg(localFilePath));
            delete m_downloadFile;
            m_downloadFile = nullptr;
            return false;
        }
    }
    
    QString command = QString("RETR %1\r\n").arg(fileName);
    m_controlSocket->write(command.toUtf8());
    return m_controlSocket->waitForBytesWritten();
}

bool FtpProtocol::sendSTOR(const QString &fileName)
{    if (!isConnected() || !establishDataConnection())
        return false;
    
    m_currentCommand = STOR; // 设置当前命令为STOR
    QString command = QString("STOR %1\r\n").arg(fileName);
    m_controlSocket->write(command.toUtf8());
    return m_controlSocket->waitForBytesWritten();
}

bool FtpProtocol::sendDELE(const QString &fileName)
{    if (!isConnected())
        return false;
    
    QString command = QString("DELE %1\r\n").arg(fileName);
    m_controlSocket->write(command.toUtf8());
    return m_controlSocket->waitForBytesWritten();
}

bool FtpProtocol::sendQUIT()
{    if (!isConnected())
        return false;
    
    m_controlSocket->write("QUIT\r\n");
    bool result = m_controlSocket->waitForBytesWritten();
    // QUIT后断开连接
    disconnectFromHost();
    return result;
}

QTcpSocket *FtpProtocol::dataSocket() const
{    return m_dataSocket;
}

int FtpProtocol::getResponseCode()
{    // 从响应缓冲区获取响应码（前三字符）
    if (m_responseBuffer.isEmpty())
        return -1;
    
    bool ok;
    int code = m_responseBuffer.left(3).toInt(&ok);
    return ok ? code : -1;
}

QString FtpProtocol::getResponseMessage()
{    return m_responseBuffer;
}

void FtpProtocol::onControlSocketReadyRead()
{    // 读取控制套接字的数据
    m_responseBuffer = m_controlSocket->readAll();
    
    // 解析响应码
    int code = getResponseCode();
    QString message = getResponseMessage();
    
    // 特殊处理PASV响应
    if (code == 227 && message.contains("Entering Passive Mode")) {
        // 解析PASV响应格式: "227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)"
        QRegExp rx("\\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)");
        if (rx.indexIn(message) != -1) {
            QString ip = QString("%1.%2.%3.%4")
                        .arg(rx.cap(1))
                        .arg(rx.cap(2))
                        .arg(rx.cap(3))
                        .arg(rx.cap(4));
            quint16 port = rx.cap(5).toInt() * 256 + rx.cap(6).toInt();
            
            m_passiveAddress = QHostAddress(ip);
            m_passivePort = port;
        }
    }
    
    // 发送响应信号
    emit responseReceived(code, message);
}

void FtpProtocol::onControlSocketDisconnected()
{    emit controlConnectionClosed();
}

void FtpProtocol::onDataSocketConnected()
{    emit dataConnectionEstablished();
}

void FtpProtocol::onDataSocketDisconnected()
{
    // 如果是RETR命令且文件已打开，关闭文件
    onDownloadFileFinish();
    m_isPassiveConnectionReused = false;
    m_currentCommand = None; // 重置当前命令
    emit dataConnectionClosed();
    // 数据连接关闭后重置被动模式信息
    m_passivePort = 0;
}

void FtpProtocol::onDownloadFileFinish()
{
    if (m_currentCommand == RETR && m_downloadFile && m_downloadFile->isOpen()) {
        m_downloadFile->close();
        delete m_downloadFile;
        m_downloadFile = nullptr;

        m_bytesReceived = 0;
    }
}

void FtpProtocol::sendCommand(const QString &command)
{
    if (m_controlSocket->isOpen()) {
        m_controlSocket->write(command.toUtf8() + "\r\n");
        m_controlSocket->flush();
    }
}

// 数据套接字可读处理
void FtpProtocol::onDataSocketReadyRead()
{
    // 读取所有可用数据
    QByteArray data = m_dataSocket->readAll();
    qDebug() << "[FTP Protocol] 收到数据:" << data.size() << "字节，当前命令:" << m_currentCommand;
    
    // 根据当前命令类型进行不同的处理
    switch (m_currentCommand) {
    case LIST:
        // LIST命令：处理文件列表数据
        qDebug() << "[FTP Protocol] 处理LIST数据";
        parseAndEmitListData(data);
        break;
        
    case RETR:
        // RETR命令：处理下载文件数据
        qDebug() << "[FTP Protocol] 处理RETR数据，大小:" << data.size() << "字节";
        if (m_downloadFile && m_downloadFile->isOpen()) {
       // 增加错误重试机制
            qint64 bytesToWrite = data.size();
            qint64 totalBytesWritten = 0;
            const char* p = data.data();
            
            // 循环写入直到所有数据都写入或遇到错误
            while (totalBytesWritten < bytesToWrite) {
                qint64 bytesWritten = m_downloadFile->write(p+totalBytesWritten,bytesToWrite - totalBytesWritten);
                if (bytesWritten < 0) {
                    emit error(tr("写入文件失败: %1").arg(m_downloadFile->errorString()));
                    m_downloadFile->close();
                    delete m_downloadFile;
                    m_downloadFile = nullptr;
                    return;
                }
                totalBytesWritten += bytesWritten;
            }
            m_bytesReceived += totalBytesWritten;
            emit downloadProgress(m_bytesReceived, m_currentFileName);

        } else {
            // 兼容原有的信号发送方式（如果没有提供本地文件路径）
            emit fileDataReceived(data);
        }
        break;
        
    case STOR:
        // STOR命令：通常不需要处理数据（上传时是我们发送数据）
        break;
    default:
        break;
    }
}

// 解析LIST数据并发送信号
void FtpProtocol::parseAndEmitListData(const QByteArray &data)
{
    QString listString = QString::fromUtf8(data);
    QStringList lines = listString.split("\n", Qt::SkipEmptyParts);
    
    QList<QStringList> fileInfoList;

    foreach(QString line, lines) {
        line = line.trimmed();
        if (line.isEmpty()) continue;

        QStringList fileInfo;

        // 解析FTP列表行
        // 格式如: -rwxr-xr-x    1 0        0             881 Sep 29 17:37 1.kmz
        QStringList parts = line.split(QRegExp("\\s+"), Qt::SkipEmptyParts);
        int nCol = parts.size();
        if (nCol >= 8) {
            // 确定是否为目录
            QString type = (parts[0].startsWith('d')) ? "目录" : "文件";

            // 文件名 (可能包含空格，所以需要特殊处理)
            QString filename;
            bool bFewField = nCol == 8;
            int nameIndex = bFewField ? 7 : 8; // 文件名通常从第9个字段开始
            while (nameIndex < parts.size()) {
                if (!filename.isEmpty()) filename += " ";
                filename += parts[nameIndex];
                nameIndex++;
            }

            int startIndex = bFewField ? 3 : 4;
            // 文件大小
            QString sizeStr = parts[startIndex++];
            qint64 size = sizeStr.toLongLong();
            // 创建时间
            QString month = parts[startIndex++];
            QString day = parts[startIndex++];
            QString timeYear = parts[startIndex++];
            QString date = QString("%1 %2 %3").arg(month).arg(day).arg(timeYear);
            fileInfo.push_back(filename);
            fileInfo.push_back(type);
            fileInfo.push_back(sizeStr);
            fileInfo.push_back(date);
           
            fileInfoList.push_back(fileInfo);
        }
    } 
    
    // 发送信号
    emit listDataReceived(fileInfoList);
}

// 设置数据连接模式并发送相应命令
bool FtpProtocol::setupDataConnectionMode(bool usePasv, bool usePasv2)
{
    if (!isDataConnectionActive()) {
        if (!usePasv) {
            // 使用PORT模式
            return sendPORT();
        }
        else if (usePasv2) {
            // 使用PASV2模式
            return sendPASV2();
        }
        else {
            // 使用PASV模式
            return sendPASV();
        }
    }
    else {
        emit dataConnectionReady();
    }
    return true;
}